﻿using CTP.CRM.Application.Localization;
using CTP.CRM.Core;
using CTP.CRM.Core.Language;
using CTP.CRM.Core.Localization;
using CTP.CRM.Repository;
using Dtmcli;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Savorboard.CAP.InMemoryMessageQueue;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AutoMapper;
using Volo.Abp.EventBus.RabbitMq;
using Volo.Abp.FluentValidation;
using Volo.Abp.Http.Client;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.RabbitMQ;
using Volo.Abp.VirtualFileSystem;
using CTP.CRM.Core.SharedModel.Pub;
using CTP.CRM.Application.Interfaces.AppSercret;
using CTP.CRM.Core.Email;
using CTP.CRM.Core.SharedModel;

namespace CTP.CRM.Application
{
    //[DependsOn]属性声明模块依赖  
    [DependsOn(
    typeof(AbpAutoMapperModule),  //简化类型映射操作
    typeof(RepositoryModule),     //自定义仓储模块
    typeof(AbpFluentValidationModule), //FluentValidation验证模块
    typeof(AbpEventBusRabbitMqModule), //用于集成RabbitMQ的分布式事件总线模块，支持跨服务通信
    typeof(AbpLocalizationModule),     //本地化模块，负责实现多语言支持和本地化资源管理
    typeof(AbpVirtualFileSystemModule), //用于实现虚拟文件系统（VFS）功能，允许应用程序通过统一接口访问嵌入资源、物理文件或远程存储的文件，而无需关心底层存储细节
    typeof(AbpHttpClientModule)        //支持通过动态代理生成RESTful API请求
// typeof(LoggerCenterHttpApiModule),
//typeof(CtpUserCenterHttpApiModule), //添加用户中心模块依赖
//typeof(CtpFMCHttpApiModule), //财务中心模块依赖
//typeof(CtpContractHttpApiModule), //合同中心
//typeof(WorkflowModule), // 流程中心模块依赖
//typeof(CamsHttpApiModule), //cams3.
//typeof(FSCenterModule)
)]
    public class ApplicationModule : AbpModule
    {
        /// <summary>
        /// 配置服务
        /// 使用场景: 主要用于配置模块所需的各种服务，包括自定义选项、用户服务、数据库服务等。例如，配置字符串加密选项、用户中心令牌选项、添加服务范围等。
        /// </summary>
        /// <param name="context"></param>
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            //获取配置对象
            var configuration = context.Services.GetConfiguration();
            //配置自动映射器
            Configure<AbpAutoMapperOptions>(options =>
            {
                options.AddMaps<ApplicationModule>(true);
            });
            //配置ASP.NET Core MVC
            Configure<AbpAspNetCoreMvcOptions>(options =>
            {
                options.ConventionalControllers.Create(typeof(ApplicationModule).Assembly);//创建动态api
            });

            //配置RabbitMQ连接
            Configure<AbpRabbitMqOptions>(options =>
            {
                options.Connections.Default.HostName = configuration["RabbitMQ:HostName"];
                options.Connections.Default.UserName = configuration["RabbitMQ:UserName"];
                options.Connections.Default.Password = configuration["RabbitMQ:Password"];
                options.Connections.Default.Port = configuration.GetValue<int>("RabbitMQ:Port");
            });


            //添加分布式消息总线
            Configure<AbpRabbitMqEventBusOptions>(options =>
            {
                options.ClientName = "EventBusQueues";
                options.ExchangeName = "EventBusExchange";
            });


            //CAP
            //CAP用于支持微服务架构中的分布式事务，这段代码配置了CAP与RabbitMQ的集成。
            //如果不在调试模式下，使用MySQL作为存储，RabbitMQ作为消息队列，并配置了失败重试策略和仪表盘。
            //在调试模式下，使用内存存储和内存消息队列，简化开发环境下的配置。
            if (!System.Diagnostics.Debugger.IsAttached)
            {
                context.Services.AddCap(options =>
                {
                    options.UseMySql(configuration["ConnectionStrings:DefaultConnection"]);
                    options.UseRabbitMQ(configure =>
                    {
                        configure.HostName = configuration["RabbitMQ:HostName"];
                        configure.UserName = configuration["RabbitMQ:UserName"];
                        configure.Password = configuration["RabbitMQ:Password"];
                        configure.Port = configuration.GetValue<int>("RabbitMQ:Port");
                    });
                    options.FailedRetryInterval = 60; //每次重试的间隔时间
                    options.FailedRetryCount = 10;    //重试的最大次数
                    options.UseDashboard(options =>
                    {
                        options.PathBase = System.Diagnostics.Debugger.IsAttached ? "" : configuration["Swagger:JsonUrlPrefix"];
                        //options.PathBase = configuration["Environment"] == "Test" ? "/customerApi" : "";
                    });
                    options.FailedThresholdCallback = faileCalback =>
                    {
                        LogHelper.Error($@"{faileCalback.MessageType} 失败了,消息名称: {faileCalback.Message}");
                    };
                });
            }
            else
            {
                context.Services.AddCap(options =>
                {
                    options.UseInMemoryStorage();
                    options.UseDashboard(option =>
                    {
                        option.PathBase = System.Diagnostics.Debugger.IsAttached ? "" : configuration["Swagger:JsonUrlPrefix"];
                        //options.PathBase = configuration["Environment"] == "Test" ? "/customerApi" : "";
                    });
                    options.UseInMemoryMessageQueue();
                });
            }


            //DTM
            //DTM是一个分布式事务管理器，这段代码配置了DTM的HTTP地址、超时时间和数据库类型等参数，以支持跨服务的分布式事务管理。
            context.Services.AddDtmcli(x =>
            {
                // DTM server 的 HTTP 地址
                x.DtmUrl = "http://192.168.80.56:36789";

                // 请求 DTM server 的超时时间, 单位是毫秒
                x.DtmTimeout = 10000;

                // 请求分支事务的超时时间, 单位是毫秒
                x.BranchTimeout = 10000;

                // 子事务屏障的数据库类型, mysql, postgres, sqlserver
                x.SqlDbType = "mysql";

                // 子事务屏障的数据表名
                x.BarrierSqlTableName = "dtm_barrier";
            });

            //添加虚拟文件系统
            Configure<AbpVirtualFileSystemOptions>(options =>
            {
                options.FileSets.AddEmbedded<ApplicationModule>("CTP.CRM.Application");
            });

            //添加多语言支持
            var languageConfig = configuration.GetSection("Language");
            Configure<AbpLocalizationOptions>(options =>
            {
                options.Resources
                    .Add<CRMLocalizationResource>("zh-CN")
                    .AddBaseTypes(typeof(CtpBasicLocalization))
                    .AddRedisResource(languageConfig)
                    .AddVirtualJson("/Localization/Resources");
            });

            //主数据多语言
            context.Services.AddMasterDataLanguage(options =>
            {
                options.LanguageHeaderKey = configuration["MasterDataLanguage:LanguageHeaderKey"];
                options.MasterdataItemLanguageCacheKey = configuration["MasterDataLanguage:MasterdataItemLanguageCacheKey"];
                options.MasterdataItemLanguageDbIndex = configuration.GetValue<int>("MasterDataLanguage:MasterdataItemLanguageDbIndex");
            });

            //启用Token鉴权
            //添加了一个Token异步授权过滤器，用于在MVC选项中启用API的Token鉴权机制
            context.Services.Configure<MvcOptions>(options =>
            {
                options.Filters.Add(new ApiAsyncAuthorizationFilter());
            });




            //配置AppSecretId生成器
            Configure<AppSecretIdGeneratorOptions>(options =>
            {
                options.Base32Chars = "abcdefghijklmnopqrstuvwxyz123456";
            });

            //配置邮件服务
            context.Services.AddEmail(options =>
            {
                options.FromName = configuration["Email:FromName"];
                options.FromEmail = configuration["Email:FromEmail"];
                options.SMTPAuthorizationCode = configuration["Email:SMTPAuthorizationCode"];
            });
        }

        /// <summary>
        /// 预配置服务
        /// 使用场景: 用于在其他模块配置服务之前进行一些预配置。这些配置通常是一些基础设置，例如配置健康检查服务、AutoMapper映射、虚拟文件系统等
        /// </summary>
        /// <param name="context"></param>
        public override void PreConfigureServices(ServiceConfigurationContext context)
        {
            PreConfigure<AbpHttpClientBuilderOptions>(options =>
            {
                options.ProxyClientActions.Add(async (remoteName, serviceProvider, httpClient) =>
                {
                    try
                    {
                        //如果设置Token，前端需要传入Token 否则引发异常
                        httpClient.SetTokenHeader();
                        //如果设置需要取子系统，前端需要再请求头中传入子系统，否则引发异常
                        httpClient.SetSubSysHeader();
                        //如果设置需要取业务主体，前端需要再请求头中传入业务主体Id，否则引发异常
                        httpClient.SetBusinessHeader();
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Error("this token has error,{0}", false, ex);
                    }

                    await Task.CompletedTask;
                });
            });
        }
    }
}
